#include "findreplacedialog.h"
#include "codeeditor.h"

FindReplaceDialog::FindReplaceDialog(QWidget *parent, QTabWidget *tabWidget) : QDialog(parent)
{
    this->tabWidget = tabWidget;

    this->setFixedSize(380, 320);
    this->setFont(QFont(QStringList{"Arial", "微软雅黑"}, 11));
    this->setWindowTitle(tr("Find & Replace in current file"));
    this->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog);

    findComboBox = new QComboBox;
    upwardRadioButton = new QRadioButton(tr("Upward"));
    caseCheckBox = new QCheckBox(tr("Case Sensitive"));
    wholeWordsCheckBox = new QCheckBox(tr("Whole words only"));

    findLabel = new QLabel(tr("Text to find:"));

    replaceCheckBox = new QCheckBox(tr("Replace with:"));
    replaceComboBox = new QComboBox;

    optionsGroupBox = new QGroupBox(tr("Options"));

    directionsGroupBox = new QGroupBox(tr("Directions"));
    downwardRadioButton = new QRadioButton(tr("Downward"));

    findReplaceButton = new QPushButton(tr("Find")); //定义find按钮
    replaceAllButton = new QPushButton(tr("Replace All")); //定义replaceAll按钮
    cancelButton = new QPushButton(tr("Close")); //定义cancel按钮

    replaceComboBox->setEnabled(false);
    connect(replaceCheckBox, &QCheckBox::checkStateChanged, this, &FindReplaceDialog::replaceCheckBoxStateChanged);

    findComboBox->setEditable(true);
    findComboBox->lineEdit()->completer()->setCaseSensitivity(Qt::CaseSensitive);

    replaceComboBox->setEditable(true);
    replaceComboBox->lineEdit()->completer()->setCaseSensitivity(Qt::CaseSensitive);

    //connect(findComboBox->lineEdit(), &QLineEdit::returnPressed, this, &FindReplaceDialog::findLineEditReturnPressed);
    //connect(replaceComboBox->lineEdit(), &QLineEdit::returnPressed, this, &FindReplaceDialog::replaceLineEditReturnPressed);

    searchDialogTabWidget=new QTabWidget;
    QHBoxLayout *tabWidgetLayout=new QHBoxLayout;
    tabWidgetLayout->addWidget(searchDialogTabWidget);
    this->setLayout(tabWidgetLayout);

    QWidget *currentFileWidget=new QWidget;
    searchDialogTabWidget->addTab(currentFileWidget, tr("Current File"));

    QVBoxLayout *mainVLayout = new QVBoxLayout;
    currentFileWidget->setLayout(mainVLayout);
    mainVLayout->addWidget(findLabel);
    mainVLayout->addWidget(findComboBox);
    mainVLayout->addWidget(replaceCheckBox);
    mainVLayout->addWidget(replaceComboBox);

    QHBoxLayout *buttonsHLayout = new QHBoxLayout;
    buttonsHLayout->addStretch();
    buttonsHLayout->addWidget(findReplaceButton);
    buttonsHLayout->addWidget(replaceAllButton);
    buttonsHLayout->addWidget(cancelButton);
    buttonsHLayout->addStretch();

    replaceAllButton->setVisible(false);

    connect(findReplaceButton, &QCheckBox::clicked, this, &FindReplaceDialog::findReplaceButtonClicked);
    connect(replaceAllButton, &QCheckBox::clicked, this, &FindReplaceDialog::replaceAllButtonClicked);

    connect(cancelButton, &QCheckBox::clicked, this, &FindReplaceDialog::cancelButtonClicked);

    QVBoxLayout *optionsGroupBoxVLayout = new QVBoxLayout;
    optionsGroupBoxVLayout->addWidget(caseCheckBox);
    optionsGroupBoxVLayout->addWidget(wholeWordsCheckBox);
    optionsGroupBox->setLayout(optionsGroupBoxVLayout);

    QVBoxLayout *directionsGroupBoxVLayout = new QVBoxLayout;
    directionsGroupBoxVLayout->addWidget(upwardRadioButton);
    directionsGroupBoxVLayout->addWidget(downwardRadioButton);
    directionsGroupBox->setLayout(directionsGroupBoxVLayout);

    downwardRadioButton->setChecked(true);

    QHBoxLayout *groupBoxHLayout = new QHBoxLayout;
    groupBoxHLayout->addWidget(optionsGroupBox);
    groupBoxHLayout->addWidget(directionsGroupBox);

    mainVLayout->addLayout(groupBoxHLayout);
    mainVLayout->addLayout(buttonsHLayout);

    //----------------在打开文件中检索的界面设计-----------------------------
    openedFilesSearchLineEdit = new QLineEdit;
    openedFilesCaseCheckBox = new QCheckBox(tr("Case Sensitive"));
    openedFilesWholeWordsCheckBox = new QCheckBox(tr("Whole words only"));
    openedFilesFindReplaceButton = new QPushButton(tr("Find"));
    openedFilesCancelButton = new QPushButton(tr("Close"));

    QWidget *openedFilesWidget=new QWidget;
    searchDialogTabWidget->addTab(openedFilesWidget, tr("Opened Files"));
    QVBoxLayout *openedFilesVLayout=new QVBoxLayout;
    openedFilesWidget->setLayout(openedFilesVLayout);
    openedFilesVLayout->addWidget(new QLabel(tr("Text to find:")));
    openedFilesVLayout->addWidget(openedFilesSearchLineEdit);
    openedFilesReplaceCheckBox=new QCheckBox(tr("Replace with:"));
    openedFilesReplaceLineEdit=new QLineEdit;
    openedFilesVLayout->addWidget(openedFilesReplaceCheckBox);
    openedFilesVLayout->addWidget(openedFilesReplaceLineEdit);

    openedFilesReplaceLineEdit->setEnabled(false);
    connect(openedFilesReplaceCheckBox, &QCheckBox::checkStateChanged, this, &FindReplaceDialog::openedFilesReplaceCheckBoxStateChanged);

    QGroupBox *openedFilesOptionsGroupBox = new QGroupBox(tr("Options"));
    QHBoxLayout *openedFilesHLayout1=new QHBoxLayout;
    openedFilesOptionsGroupBox->setLayout(openedFilesHLayout1);
    openedFilesHLayout1->addWidget(openedFilesCaseCheckBox);
    openedFilesHLayout1->addWidget(openedFilesWholeWordsCheckBox);
    QHBoxLayout *openedFilesHLayout2=new QHBoxLayout;
    openedFilesHLayout2->addStretch();
    openedFilesHLayout2->addWidget(openedFilesFindReplaceButton);
    openedFilesHLayout2->addWidget(openedFilesCancelButton);
    openedFilesHLayout2->addStretch();
    openedFilesVLayout->addWidget(openedFilesOptionsGroupBox);
    openedFilesVLayout->addLayout(openedFilesHLayout2);

    connect(openedFilesCancelButton, &QCheckBox::clicked, this, &FindReplaceDialog::cancelButtonClicked);

    //----------------在当前项目中检索的界面设计-----------------------------
    projectSearchLineEdit = new QLineEdit;
    projectCaseCheckBox = new QCheckBox(tr("Case Sensitive"));
    projectWholeWordsCheckBox = new QCheckBox(tr("Whole words only"));
    projectFindReplaceButton = new QPushButton(tr("Find"));
    projectCancelButton = new QPushButton(tr("Close"));

    QWidget *projectWidget=new QWidget;
    searchDialogTabWidget->addTab(projectWidget, tr("Current Project"));
    QVBoxLayout *projectVLayout=new QVBoxLayout;
    projectWidget->setLayout(projectVLayout);
    projectVLayout->addWidget(new QLabel(tr("Text to find:")));
    projectVLayout->addWidget(projectSearchLineEdit);
    projectReplaceCheckBox=new QCheckBox(tr("Replace with:"));
    projectReplaceLineEdit=new QLineEdit;
    projectVLayout->addWidget(projectReplaceCheckBox);
    projectVLayout->addWidget(projectReplaceLineEdit);

    projectReplaceLineEdit->setEnabled(false);
    connect(projectReplaceCheckBox, &QCheckBox::checkStateChanged, this, &FindReplaceDialog::projectReplaceCheckBoxStateChanged);

    QGroupBox *projectOptionsGroupBox = new QGroupBox(tr("Options"));
    QHBoxLayout *projectHLayout1=new QHBoxLayout;
    projectOptionsGroupBox->setLayout(projectHLayout1);
    projectHLayout1->addWidget(projectCaseCheckBox);
    projectHLayout1->addWidget(projectWholeWordsCheckBox);
    QHBoxLayout *projectHLayout2=new QHBoxLayout;
    projectHLayout2->addStretch();
    projectHLayout2->addWidget(projectFindReplaceButton);
    projectHLayout2->addWidget(projectCancelButton);
    projectHLayout2->addStretch();
    projectVLayout->addWidget(projectOptionsGroupBox);
    projectVLayout->addLayout(projectHLayout2);

    connect(projectCancelButton, &QCheckBox::clicked, this, &FindReplaceDialog::cancelButtonClicked);

    searchDialogTabWidget->setCurrentIndex(0);
    //searchDialogTabWidget改变当前页的信号处理连接
    connect(searchDialogTabWidget, &QTabWidget::currentChanged, this, &FindReplaceDialog::currentTabChanged);
}

void FindReplaceDialog::currentTabChanged(int index)
{
    if (index==1)
    {
        this->setFixedSize(380, 300);
        this->setWindowTitle(tr("Find & Replace in opened files"));
        openedFilesSearchLineEdit->setFocus();
        openedFilesSearchLineEdit->setSelection(0, openedFilesSearchLineEdit->text().size());
    }
    else if (index==2)
    {
        this->setFixedSize(380, 300);
        this->setWindowTitle(tr("Find & Replace in current project"));
        projectSearchLineEdit->setFocus();
        projectSearchLineEdit->setSelection(0, projectSearchLineEdit->text().size());
    }
    else
    {
        this->setFixedSize(380, 320);
        this->setWindowTitle(tr("Find & Replace in current file"));
        findComboBox->setFocus();
        replaceCheckBox->setChecked(replaceOn);
        findComboBox->lineEdit()->setSelection(0, findComboBox->lineEdit()->text().size());
    }
}

void FindReplaceDialog::showEvent(QShowEvent *event)
{
    if (findComboBox->isVisible())
    {
        findReplaceButton->setFocus();
        findComboBox->setFocus();
        replaceCheckBox->setChecked(replaceOn);
        findComboBox->lineEdit()->setSelection(0, findComboBox->lineEdit()->text().size());
    }
    else if (openedFilesSearchLineEdit->isVisible())
    {
        openedFilesSearchLineEdit->setFocus();
        openedFilesSearchLineEdit->setSelection(0, openedFilesSearchLineEdit->text().size());
    }
    else if (projectSearchLineEdit->isVisible())
    {
        projectSearchLineEdit->setFocus();
        projectSearchLineEdit->setSelection(0, projectSearchLineEdit->text().size());
    }

    QDialog::showEvent(event);
}

void FindReplaceDialog::replaceCheckBoxStateChanged(Qt::CheckState state)
{
    replaceComboBox->setEnabled(state==Qt::Checked);
    replaceAllButton->setVisible(state==Qt::Checked);
    findReplaceButton->setText(state == Qt::Unchecked ? tr("Find") : tr("Find/Replace"));
}

void FindReplaceDialog::projectReplaceCheckBoxStateChanged(Qt::CheckState state)
{
    projectReplaceLineEdit->setEnabled(state==Qt::Checked);
    projectFindReplaceButton->setText(state == Qt::Unchecked ? tr("Find") : tr("Replace"));
}

void FindReplaceDialog::openedFilesReplaceCheckBoxStateChanged(Qt::CheckState state)
{
    openedFilesReplaceLineEdit->setEnabled(state==Qt::Checked);
    openedFilesFindReplaceButton->setText(state == Qt::Unchecked ? tr("Find") : tr("Replace"));
}

void FindReplaceDialog::findLineEditReturnPressed()
{
    findReplaceButtonClicked();
}

void FindReplaceDialog::replaceLineEditReturnPressed()
{
    findReplaceButtonClicked();
}

void FindReplaceDialog::replaceAllButtonClicked()
{
    QWidget *widget = tabWidget->currentWidget();
    if (widget)
    {
        CodeEditor *editor = dynamic_cast<CodeEditor *>(widget);
        QString findString = findComboBox->currentText();

        QTextDocument::FindFlags options;
        if (upwardRadioButton->isChecked())
            options = QTextDocument::FindBackward;
        if (caseCheckBox->isChecked())
            options = options | QTextDocument::FindCaseSensitively;
        if (wholeWordsCheckBox->isChecked())
            options = options | QTextDocument::FindWholeWords;

        QTextCursor textCursor = editor->textCursor();
        textCursor.beginEditBlock();
        QTextCursor cursor = editor->document()->find(findString, 0, options);
        int count = 0;
        while (!cursor.isNull())
        {
            cursor.insertText(replaceComboBox->currentText());
            cursor = editor->document()->find(findString, cursor, options);
            count++;
        }
        textCursor.endEditBlock();
        editor->update();
        QApplication::beep();
        QMessageBox::information(this, "Information", QString::number(count) + tr(" matches have been replaced."));
    }
}

void FindReplaceDialog::findReplaceButtonClicked()
{
    //disconnect(findComboBox->lineEdit(), &QLineEdit::returnPressed, this, &FindReplaceDialog::findLineEditReturnPressed);
    // emit findComboBox->lineEdit()->returnPressed();
    // connect(findComboBox->lineEdit(), &QLineEdit::returnPressed, this, &FindReplaceDialog::findLineEditReturnPressed);
    // disconnect(replaceComboBox->lineEdit(), &QLineEdit::returnPressed, this, &FindReplaceDialog::replaceLineEditReturnPressed);
    // emit replaceComboBox->lineEdit()->returnPressed();
    // connect(replaceComboBox->lineEdit(), &QLineEdit::returnPressed, this, &FindReplaceDialog::replaceLineEditReturnPressed);

    QWidget *widget = tabWidget->currentWidget();
    if (widget)
    {
        CodeEditor *editor = dynamic_cast<CodeEditor *>(widget);
        QString findString = findComboBox->currentText();
        if (findString.isEmpty())
        {
            QMessageBox::information(this, "Find && Replace", tr("Please input a string to search!"));
            return;
        }

        QTextDocument::FindFlags options;
        if (upwardRadioButton->isChecked())
            options = QTextDocument::FindBackward;
        if (caseCheckBox->isChecked())
            options = options | QTextDocument::FindCaseSensitively;
        if (wholeWordsCheckBox->isChecked())
            options = options | QTextDocument::FindWholeWords;

        if (replaceCheckBox->isChecked())
        {
            QString selectedText = editor->textCursor().selectedText(); //根据起始位置和长度获取选中的文本
            if (QString::compare(selectedText, findString, caseCheckBox->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive) == 0)
            {
                editor->insertPlainText(replaceComboBox->currentText());
            }
        }

        bool found = editor->find(findString, options);
        if (!found)
        {
            //QMessageBox::information(this, "Information", findString.toHtmlEscaped()+"<p>"+tr("The above string was not found!"));
            QMessageBox msg(this);
            msg.setTextFormat(Qt::PlainText);
            msg.setIcon(QMessageBox::Information);
            msg.setWindowTitle(tr("Search Result"));
            msg.setText(findString+"\n\n"+tr("The above string was not found!"));
            msg.exec();
        }
    }
}

void FindReplaceDialog::cancelButtonClicked()
{
    //this->setVisible(false);
    this->reject();//Cancel按钮点击以后发出Rejected返回值
}
